package net.lab0.nebula.gui;

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import java.security.NoSuchAlgorithmException;

import javax.swing.JCheckBoxMenuItem;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JTabbedPane;
import javax.swing.SwingWorker;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.filechooser.FileFilter;

import net.lab0.nebula.core.QuadTreeManager;
import net.lab0.nebula.data.QuadTreeNode;
import net.lab0.nebula.exception.InvalidBinaryFileException;
import net.lab0.nebula.listener.QuadTreeManagerListener;
import nu.xom.ParsingException;
import javax.swing.ImageIcon;

@SuppressWarnings("serial")
public class MainWindow
extends JFrame
{
    private QuadTreeManager   quadTreeManager;
    
    private MainPanel         mainPanel;
    private StatisticsPanel   statisticsPanel;
    
    private ComputationPanel  computationPanel;
    
    private RenderingPanel    renderingPanel;
    
    private MapPanel          pnlMap;
    
    private JCheckBoxMenuItem chckbxmntmUseOpencl;
    
    private StatusBar         pnlStatus;
    
    public MainWindow()
    {
        // select Look and Feel
        try
        {
            UIManager.setLookAndFeel("com.jtattoo.plaf.acryl.AcrylLookAndFeel");
        }
        catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException e1)
        {
            try
            {
                UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
            }
            catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException e2)
            {
                // no laf change
            }
        }
        
        setTitle("Mandelbrot QTree compute manager");
        getContentPane().setLayout(new BorderLayout(0, 0));
        
        pnlStatus = new StatusBar();
        getContentPane().add(pnlStatus, BorderLayout.SOUTH);
        
        JTabbedPane tabbedPane = new JTabbedPane(JTabbedPane.TOP);
        getContentPane().add(tabbedPane, BorderLayout.CENTER);
        
        mainPanel = new MainPanel(this);
        tabbedPane.addTab("Main", null, mainPanel, null);
        
        statisticsPanel = new StatisticsPanel(this);
        tabbedPane.addTab("Statistics", null, statisticsPanel, null);
        
        computationPanel = new ComputationPanel(this);
        tabbedPane.addTab("Computation", null, computationPanel, null);
        
        renderingPanel = new RenderingPanel(this);
        tabbedPane.addTab("Rendering", null, renderingPanel, null);
        
        pnlMap = new MapPanel(this);
        tabbedPane.addTab("Map", null, pnlMap, null);
        
        JMenuBar menuBar = new JMenuBar();
        setJMenuBar(menuBar);
        
        JMenu mnFile = new JMenu("File");
        menuBar.add(mnFile);
        
        JMenuItem mntmOpen = new JMenuItem("Open...");
        mntmOpen.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                openFile();
            }
        });
        
        JMenuItem mntmOpenTestFile = new JMenuItem("My open ...");
        mntmOpenTestFile.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                myOpenFile();
            }
        });
        
        JMenu mnNew = new JMenu("New");
        mnNew.setIcon(new ImageIcon(MainWindow.class.getResource("/com/jtattoo/plaf/icons/NewFolder.gif")));
        mnFile.add(mnNew);
        
        JMenuItem mntmQuadTree = new JMenuItem("QuadTree...");
        mntmQuadTree.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                NewQuadTreeWizzard wizzard = new NewQuadTreeWizzard(MainWindow.this);
                wizzard.setLocationRelativeTo(null);
                wizzard.setVisible(true);
                
                if (wizzard.isApproved())
                {
                    quadTreeManager = new QuadTreeManager(new QuadTreeNode(-2.0, 2.0, -2.0, 2.0), wizzard.getPointsPerSide(), wizzard.getMaxIter(), wizzard
                    .getDiffIterLimit(), wizzard.getMaxDepth());
                }
            }
        });
        mnNew.add(mntmQuadTree);
        mnFile.add(mntmOpenTestFile);
        mnFile.add(mntmOpen);
        
        JMenuItem mntmSaveAs = new JMenuItem("Save as...");
        mnFile.add(mntmSaveAs);
        
        JMenuItem mntmExit = new JMenuItem("Exit");
        mnFile.add(mntmExit);
        
        JMenu mnStatistics = new JMenu("Statistics");
        menuBar.add(mnStatistics);
        
        JMenuItem mntmUpdateStatistics = new JMenuItem("Update statistics");
        mntmUpdateStatistics.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                updateStatistics();
            }
        });
        mnStatistics.add(mntmUpdateStatistics);
        
        JMenu mnComputation = new JMenu("Computation");
        menuBar.add(mnComputation);
        
        JMenuItem mntmStartresumeBackgroundComputation = new JMenuItem("Start/Resume background computation ...");
        mntmStartresumeBackgroundComputation.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                //TODO : new start / resume wizard
            }
        });
        mnComputation.add(mntmStartresumeBackgroundComputation);
        
        chckbxmntmUseOpencl = new JCheckBoxMenuItem("Use openCL");
        mnComputation.add(chckbxmntmUseOpencl);
        
        JMenu mnMap = new JMenu("Map");
        menuBar.add(mnMap);
        
        JMenu mnRendering = new JMenu("Rendering");
        menuBar.add(mnRendering);
        
        JMenuItem mntmStartRenderingPreview = new JMenuItem("Update preview");
        mntmStartRenderingPreview.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                renderingPanel.updateNebulabrotPreview();
            }
        });
        mnRendering.add(mntmStartRenderingPreview);
        
        JMenuItem mntmExport = new JMenuItem("Export...");
        mntmExport.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                renderingPanel.showRenderingExportFrame();
            }
        });
        mnRendering.add(mntmExport);
        
        mainPanel.updateTreeInformations();
        this.createDefaultTree();
    }
    
    private void createDefaultTree()
    {
        quadTreeManager = new QuadTreeManager(new QuadTreeNode(-2.0, 2.0, -2.0, 2.0), 256, 4096, 5, 10);
    }
    
    private void myOpenFile()
    {
        JFileChooser fc = new JFileChooser("F:\\dev\\nebula\\tree");
        
        fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
        
        FileFilter indexFileFilter = new FileFilter()
        {
            @Override
            public String getDescription()
            {
                return "Index files";
            }
            
            @Override
            public boolean accept(File f)
            {
                return f.isDirectory() || "index.xml".equals(f.getName());
            }
        };
        fc.setFileFilter(indexFileFilter);
        
        int ret = fc.showOpenDialog(this);
        switch (ret)
        {
            case JFileChooser.APPROVE_OPTION:
                final File f = fc.getSelectedFile();
                SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>()
                {
                    @Override
                    protected Void doInBackground()
                    throws Exception
                    {
                        quadTreeManager = new QuadTreeManager(f.getParentFile().toPath(), new QuadTreeManagerListener()
                        {
                            
                            @Override
                            public void threadStarted(long threadId)
                            {
                            }
                            
                            @Override
                            public void threadSleeping(long threadId)
                            {
                            }
                            
                            @Override
                            public void threadResumed(long threadId)
                            {
                            }
                            
                            @Override
                            public void loadingFile(int current, int total)
                            {
                                setStatus("Loading", null, (float) current / (float) total);
                            }
                            
                            @Override
                            public void computeProgress(int current, int total)
                            {
                            }
                            
                            @Override
                            public void computationFinished(boolean remaining)
                            {
                            }
                        });
                        
                        return null;
                    }
                    
                    @Override
                    protected void done()
                    {
                        // TODO : treat exception
                        
                        mainPanel.updateTreeInformations();
                        updateStatistics();
                    }
                };
                
                worker.execute();
                break;
            
            default:
                break;
        }
    }
    
    private void openFile()
    {
        JFileChooser fc = new JFileChooser(".");
        
        fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
        
        FileFilter indexFileFilter = new FileFilter()
        {
            @Override
            public String getDescription()
            {
                return "Index files";
            }
            
            @Override
            public boolean accept(File f)
            {
                return f.isDirectory() || "index.xml".equals(f.getName());
            }
        };
        fc.setFileFilter(indexFileFilter);
        
        int ret = fc.showOpenDialog(this);
        switch (ret)
        {
            case JFileChooser.APPROVE_OPTION:
                File f = fc.getSelectedFile();
                try
                {
                    quadTreeManager = new QuadTreeManager(f.getParentFile().toPath(), new QuadTreeManagerListener()
                    {
                        
                        @Override
                        public void threadStarted(long threadId)
                        {
                            
                        }
                        
                        @Override
                        public void threadSleeping(long threadId)
                        {
                            
                        }
                        
                        @Override
                        public void threadResumed(long threadId)
                        {
                            
                        }
                        
                        @Override
                        public void loadingFile(int current, int total)
                        {
                            setStatus("Loading", null, (float) current / (float) total);
                        }
                        
                        @Override
                        public void computeProgress(int current, int total)
                        {
                            
                        }
                        
                        @Override
                        public void computationFinished(boolean remaining)
                        {
                            
                        }
                    });
                    mainPanel.updateTreeInformations();
                    updateStatistics();
                }
                catch (IOException | ParsingException | ClassNotFoundException | InvalidBinaryFileException | NoSuchAlgorithmException e)
                {
                    JOptionPane.showMessageDialog(this, e.toString(), "Error while loading given file", JOptionPane.ERROR_MESSAGE);
                }
                break;
            
            default:
                break;
        }
    }
    
    public QuadTreeManager getQuadTreeManager()
    {
        return quadTreeManager;
    }
    
    public void showNoQuadTreeError()
    {
        JOptionPane.showMessageDialog(this, "Please load a quad tree before doing this operation", "No quad tree loaded", JOptionPane.ERROR_MESSAGE);
    }
    
    public void updateStatistics()
    {
        statisticsPanel.updateStatisticsPanel();
    }
    
    public boolean useOpenCL()
    {
        return chckbxmntmUseOpencl.isSelected();
    }
    
    public void setStatus(String statusName, String description, float progress)
    {
        pnlStatus.setText(statusName, description);
        pnlStatus.setProgress(progress);
    }
}
